﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using InductBase;
using SharpBolt.Graphics.GraphicInstances;

namespace SharpBolt.Graphics.Particles
{
    public class ParticleContainer
    {
        public Random Random;
        public List<Particle> Particles { get; set; }

        public ParticleContainer()
        {
            Particles = new List<Particle>();
            Random = new System.Random();
        }

        public void Burst(int number, ParticleScheme scheme, Rec area)
        {
            for (int i = 0; i < number; i++)
            {
                EmittParticle(
                    area.Location
                    + new Vec2(
                    Random.NextDouble() * area.Width,
                    Random.NextDouble() * area.Height),
                    scheme,
                    area
                    );
            }
        }

        public Particle EmittParticle(Vec2 location, ParticleScheme scheme, Rec Area)
        {
            Particle particle = null;

            if (Particles.Count > scheme.MaxParticlesNumber)
            {
                particle = Particles.Find(p => p.IsDropped);

                if (particle == null)
                    return null;
            }
            else
            {
                particle = new Particle();                
                Particles.Add(particle);
            }

            particle.CurrentTime = 0;
            particle.SpriteInstance = new SpriteInstance(scheme.SpriteSource);
            particle.SpriteInstance.Speed = scheme.SpriteAnimationSpeed;
            particle.SpriteInstance.CurrentSequenceIndex = Random.Next(0, scheme.SpriteSource.Sequences.Count - 1);
            particle.Position = location;            
            particle.Lifetime = (long)(scheme.LifeTime + (0.5 - Random.NextDouble()) * scheme.RandLifeTime);
            if (particle.Lifetime < 1) particle.Lifetime = 1;
            particle.IsDropped = false;
            particle.Scheme = scheme;

            if (scheme.OutOfCenter)
            {
                particle.Direction = (location - Area.Center).Normalized();
            }
            else
            {
                particle.Direction = new Vec2(1, 0).Rotate(scheme.SpreadAngle + (Random.NextDouble()-0.5) * scheme.RandSpreadAngle);
            }

            return particle;
        }

        public void UpdateParticles(double delta)
        {
            foreach (Particle particle in Particles)
            {
                if (particle.IsDropped) continue;

                double part = (double)particle.CurrentTime / particle.Lifetime;

                //if (particle.Scheme.EasingMethod != null)
                //    part = particle.Scheme.EasingMethod(part);

                int indexA = (int)((particle.Scheme.Nodes.Count - 1) * part);
                if (indexA < 0) indexA = 0;
                ParticleStateNode NodeR = particle.Scheme.Nodes[indexA];

                if (part < 1)
                {
                    ParticleStateNode NodeA = particle.Scheme.Nodes[indexA];
                    ParticleStateNode NodeB = particle.Scheme.Nodes[indexA + 1];

                    double nodePartLength = 1.0 / (particle.Scheme.Nodes.Count - 1);
                    double nodePart = (part - indexA * nodePartLength) / nodePartLength;
                    NodeR = ParticleStateNode.GetStateByPart(nodePart, NodeA, NodeB);
                }
                

                particle.SpriteInstance.Transformation.Scale = NodeR.Scale;
                particle.SpriteInstance.Color = NodeR.DColor.ToColor();

                particle.SpriteInstance.Transformation.Rotation += delta / 1000.0 * NodeR.Angle;
                particle.SpriteInstance.Transformation.Rotation = particle.SpriteInstance.Transformation.Rotation % 360.0;

                particle.Position += delta * NodeR.Speed / 1000.0 * particle.Direction;


                particle.SpriteInstance.Transformation.Position = particle.Position;

                particle.SpriteInstance.Transformation.Shift = -0.5 * particle.SpriteInstance.Size;

                if (particle.Scheme.SpriteAnimationScale > 0)
                {
                    particle.Scheme.SpriteAnimationSpeed = 0;

                    double framePart = (particle.Scheme.SpriteAnimationScale * part) % 1;

                    double index = framePart * (particle.SpriteInstance.CurrentSequence.Frames.Count - 1);

                    particle.SpriteInstance.CurrentFrameIndex = (int)(index);
                }

                particle.CurrentTime += delta;
                if (particle.CurrentTime >= particle.Lifetime)
                {
                    particle.CurrentTime = particle.Lifetime;
                    particle.IsDropped = true;
                }
            }
        }

        public void Draw(Painter painter)
        {
            foreach (var particle in Particles)
            {
                if (!particle.IsDropped)
                    particle.SpriteInstance.Draw(painter);
            }
        }
    }
}
